/* 
 * File:   TriangleMesh.cpp
 * Author: brady
 * 
 * Created on August 27, 2011, 3:24 AM
 */

#include <shapes/TriangleMesh.h>
#include <acceleration/IntersectionStructure.h>
#include <acceleration/ShapeList.h>
#include <acceleration/VoxelGrid.h>
#include <acceleration/BoundingVolumeHierarchy.h>
#include <dto/RenderParams.h>

TriangleMesh::TriangleMesh() {
    if (gParams.acceleration == "vg" || gParams.acceleration == "VG") {
        triangles = new VoxelGrid();
    }
    else if (gParams.acceleration == "bvh" || gParams.acceleration == "BVH") {
        triangles = new BoundingVolumeHierarchy();
    }
    else if (gParams.acceleration == "sl" || gParams.acceleration == "sl") {
        triangles = new ShapeList();
    }
    else triangles = new ShapeList();
    
    triangleList = vector<Triangle*>();
    minVals = Vector3D(DBL_MAX, DBL_MAX, DBL_MAX);
    maxVals = Vector3D(DBL_MIN, DBL_MIN, DBL_MIN);
    material="";
}

TriangleMesh::TriangleMesh(const TriangleMesh& orig) {
    this->triangles = orig.triangles;
    this->triangleList = orig.triangleList;
    this->material = orig.material;
}

TriangleMesh::~TriangleMesh() {
    delete triangles;
}

bool TriangleMesh::testIntersect(IntersectionParams& ip, IntersectionResult& ir){
    ir.set(triangles->getFirstIntersection(ip));
    if(ir.shape != NULL){
        return true;
    }
    else return false;
}



void TriangleMesh::addTriangle(Vertex* v1, Vertex* v2, Vertex* v3){

    Triangle* triangle = new Triangle(v1, v2, v3);
    triangle->setShader(this->shader);
    triangleList.push_back(triangle);
    
    double minX = min(min(min(minVals[0], v1->location[0]), v2->location[0]), v3->location[0]);
    double minY = min(min(min(minVals[1], v1->location[1]), v2->location[1]), v3->location[1]);
    double minZ = min(min(min(minVals[2], v1->location[2]), v2->location[2]), v3->location[2]);

    double maxX = max(max(max(maxVals[0], v1->location[0]), v2->location[0]), v3->location[0]);
    double maxY = max(max(max(maxVals[1], v1->location[1]), v2->location[1]), v3->location[1]);
    double maxZ = max(max(max(maxVals[2], v1->location[2]), v2->location[2]), v3->location[2]);

    minVals = Vector3D(minX, minY, minZ);
    maxVals = Vector3D(maxX, maxY, maxZ);
}

void TriangleMesh::finalize(){
    boundingBox = BoundingBox(minVals, maxVals);
    boundingBox.pad(FLT_EPSILON);
    for(int i = 0; i<triangleList.size(); i++){
        triangleList[i]->setShader(this->shader);
        triangles->addShape(triangleList[i]);
    }
    triangles->finalize();
}
